#include "write_data.hh"
#include <sstream>
//#include <jaula.h>

using namespace std;
//using namespace JAULA;

std::ostream& write_header(const std::string name, std::ostream& out) {
  out << "\n\x01" << name << '\x02';
  return out;
}

std::ostream& write(const std::string& name, const std::vector<std::string>& vec, std::ostream& out) {
  write_header(name, out);
  for(auto it = vec.begin(); it != vec.end(); ++it) {
    out << *it << "\x01e\n";
  }
  return out << '\x03';
}

template<class T>
std::ostream& write(const std::string& name, const std::vector<T>& vec, std::ostream& out) {
  write_header(name, out);
  for(auto it = vec.begin(); it != vec.end(); ++it) {
    write("\n", *it, out);
  }
  return out << '\x03';  
}

std::ostream& write(const std::string& name, const std::map<std::string,int>& vec, std::ostream& out) {
  write_header(name, out);
  for(auto it = vec.begin(); it != vec.end(); ++it) {
    out << it->first << '\x1f' << it->second << "\x1e\n";
  }
  return out << '\x03';
}


std::ostream& write(const std::string& name, const std::map<int,int>& vec, std::ostream& out) {
  write_header(name, out);
  for(auto it = vec.begin(); it != vec.end(); ++it) {
    out << it->first << ' ' << it->second << '\x1e';
  }
  return out << '\x03';
}


std::ostream& write(const std::string& name, const std::map<std::string,std::string> &vec, std::ostream& out) {
  write_header(name, out);
  for(auto it = vec.begin(); it != vec.end(); ++it) {
    out << it->first << '\x1f' << it->second << '\x1e';
  }
  return out << '\x03';
}

std::ostream& write(const std::string& name, const Cmd& vec, std::ostream& out) {
  ostringstream commstr;

  write_header(name, out);
  if(isalpha(vec.c)) {
    commstr << static_cast<char>(vec.c);
  } else {
    commstr << '$' << hex << vec.c;
  }
  out << commstr.str() << ' '
      << vec.p1 << ' '
      << vec.p2;
  return out << '\x03';  
}

std::ostream& write(const std::string& name, const Event& vec, std::ostream& out) {
  write_header(name, out);
  out << vec.verb << ' '
      << vec.adverb << ' '
      << vec.obj1 << ' '
      << vec.adj1 << ' '
      << vec.obj2 << ' '
      << vec.adj2 << '\x1e';
  write("conditions", vec.conditions, out);
  write("actions", vec.actions, out);
  return out << '\x03';  
}


std::ostream& write(const std::string& name, const Location& vec, std::ostream& out) {
  write_header(name, out);
  out << vec.desc_short << '\x1e'
      << vec.desc_long << '\x1e'
      << vec.visited << '\x1e';
  write("exits", vec.exits, out);
  return out << '\x03';  
}


std::ostream& write(const std::string& name, const Object& vec, std::ostream& out) {
  write_header(name, out);
  out << vec.pos << '\x1e'
      << vec.weight << '\x1e'
      << vec.name << '\x1e'
      << vec.desc << '\x1e';
  return out << '\x03';  
}

std::ostream& write(const std::string& name, const std::vector<Object>& vec, std::ostream& out) {
  write_header(name, out);
  for(auto it = vec.begin(); it != vec.end(); ++it) {
    write("\n", *it, out);
  }
  return out << '\x03';  
}

std::ostream& write(const std::string& name, const Adventure& vec, std::ostream& out) {
  write_header(name, out);
  write("objects", vec.objects, out);
  write("verbs", vec.verbs, out);
  write("events", vec.events, out);
  write("msgs", vec.msgs, out);
  write("locations", vec.locations, out);
  return out << '\x03';
}


ostream& write_locations(ostream& out, const Adventure& adv) {
  out << "\x01locations\x02";
  out << '\x03';
  return out;
}

/*
  Adventure
  turns 0
  here 0 
  points 0
  end 0
  dead 0
  \x01events\x02 ... \x03
  \x01locations\x02 ... \x03

  Adventure
  * turns, here, points, end, dead
  * events
  * locations
  * objects
  ** [ (pos, weight, name, desc), ... ]
  * verbs
  ** [ (num, verb), ... ]
  * msgs
  ** [ (num, msg), ... ]
  * switches
  ** [ (num, bool), ... ]
  * counters
  ** [ (num, int), ... ]
 */
